import { Injectable, Scope } from '@nestjs/common';
import OfficialAccount from 'node-easywechat/dist/OfficialAccount/Application';
import Payment from 'node-easywechat/dist/Payment/Application';
import { JsonApiResponse } from '@utils/json.api.response';
import { InjectQueue, Process, Processor } from '@nestjs/bull';
import { Job, Queue } from 'bull';
import { OfficeNewsSendRecords } from '@databases/entities/OfficeNewsSendRecords';

import { knext } from 'knext';
import { InjectEntityManager, InjectMikroORM } from '@mikro-orm/nestjs';
import { EntityManager, MikroORM } from '@mikro-orm/mysql';
import dayjs from 'dayjs';
import { OfficePosts } from '@databases/entities/OfficePosts';
import { OfficeNews } from '@databases/entities/OfficeNews';
import { join } from 'path';
import { OfficeAccounts } from '@databases/entities/OfficeAccounts';
import MiniProgram from 'node-easywechat/dist/MiniProgram/Application';

class OfficialAccountTemplate extends OfficialAccount {
    constructor(config){
        super({
            ...config,
            // 配置项
            // debug:true,
            http:{
                proxy : {
                    protocol:'http',
                    host: '134.175.224.228',
                    port: 7908
                }
            },
            // 缓存以文件(默认设置)存储时，需要的配置项
            file_cache: {
                path: './cache/', // 文件存储目录（请确保该目录有读写权限）
                fileMode: 0o666,  // 文件权限
                dirMode: 0o777 ,
                ext: '.cache'     // 文件扩展名
            },
            // 网页授权认证
            oauth: {
                // 网页授权类型
                scope: 'snsapi_userinfo',
                // 网页授权回调地址，完整的URL
                callback: 'http://node-easywechat.hpyer.cn/wxlogin/callback'
            }
        })
    }
}

@Processor('office_queue')
@Injectable({ scope: Scope.REQUEST })
export class WeixinService {
    payClient = new Payment({
        // 应用的 app_id
       app_id: 'wx7075f04edc923e5b',
       // 商户号
       mch_id: '1558656881',
       // 签名密钥
       key: 'WAOXZJXHYLVHZYLLNUDWABGAXUHIQQAD',//APIV3:'7Q6SHV94NFHYORXGEJ8E4XQPMC3TK0GS',
       apiv3_key: '7Q6SHV94NFHYORXGEJ8E4XQPMC3TK0GS',
       // 默认回调地址，也可以在下单时单独设置来覆盖它，完整URL，不带参数
       notify_url: 'https://www.apesk.net/api/common/wxpay/callback/',
       cert_path:'/www/wwwroot/nest.apesk.net/cert/wxpay/apiclient_cert.p12',
       //sandbox : true
   })


   officialAccount = new OfficialAccountTemplate({
        // app_id : 'wxdbc056265f3d3392',
        // secret : '6c037a27e66bac485b71c97d5a6340d9',
        // token: '',

        // app_id : 'wxc6e97154dd42c8d6', //测试号
        // secret : '12c44294b4f94ebc94a6d9c738999149',
        // token  : '7IVajA4QZxEjNC8XzZzmcYYOb7twvFXk',

        app_id : 'wxd96f2c1982b61eb2', // 麦微-招聘
        secret : 'd16523ef6c83a4796853dab4eb79671b',
        token: 'ZEJiycTmUyHzsPEFxEJtTBSOSLgrgXzd',
    })

    wxMiniApp =  new MiniProgram({
        // 麦微小程序
        app_id : 'wx9811e630793238f4',
        secret : '4ebaebf58ac55c83455bec50982b6f88'

        // 配置项
        // app_id : 'wx7075f04edc923e5b',//桔赞
        // secret : '6de604c134d247e678fecbd9b7d814af'
    })

    constructor(
        @InjectMikroORM('zp')
        private readonly orm: MikroORM,
        @InjectEntityManager('zp')
        private readonly em: EntityManager,
        @InjectQueue('office_queue') private queue : Queue
    ){
            //账号是否有效
            //this.weixinService.officialAccount.client.getAccessToken()
    
            
    }

    //回调处理
    async callback(params){
        console.log('收到:--回调信息--')
        const echostr = params.echostr
        return echostr
    }

    //重置API调用限制
    async clearQuota() {
        try {
            const res = await this
            .officialAccount
            .getClient()
            .httpPostJson('https://api.weixin.qq.com/cgi-bin/clear_quota', {
                appid: this.officialAccount.config.app_id
            })

            if(res.errcode) 
                throw new Error(res.errmsg)
            else
              return res
        } catch (error) {
            throw error
        }
    }

    //获取永久带参数二维码
    async officeQrcode(params) {
        try {
            const res = await this
            .officialAccount
            .getClient()
            .httpPostJson('https://api.weixin.qq.com/cgi-bin/qrcode/create',params)

            //{"ticket":"gQGX7zwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAycjJiUHR4eGhmMkcxMDAwMHcwM3YAAgRMZDtlAwQAAAAA","url":"http://weixin.qq.com/q/02r2bPtxxhf2G10000w03v"}
            return res
        } catch (error) {
            throw new Error(JSON.stringify({error:error.messages}))
        }
    }

    //通过ticket换取二维码
    async ticket2Qrcode() {
        try {
            const res = await this
            .officialAccount
            .getClient()
            .request({
                url:'https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=gQGX7zwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAycjJiUHR4eGhmMkcxMDAwMHcwM3YAAgRMZDtlAwQAAAAA',
                method: 'GET',
                responseType: 'arraybuffer' //响应类型决定res.data 返回的数据类型 string | arraybuffer | uint8array
            })

            //{"ticket":"gQGX7zwAAAAAAAAAAS5odHRwOi8vd2VpeGluLnFxLmNvbS9xLzAycjJiUHR4eGhmMkcxMDAwMHcwM3YAAgRMZDtlAwQAAAAA","url":"http://weixin.qq.com/q/02r2bPtxxhf2G10000w03v"}
            return JsonApiResponse.OK()
        } catch (error) {
            console.log(error)
            return JsonApiResponse.object(error)
        }
    }

    //上传临时媒体(图片、视频、音频)
    // paths = [/www/wwwroot/xxxxxx/xx.jpg,]
    async uploadTempMedia(path)
    {
        const res = await this.officialAccount
        .getClient()
        .httpUpload('https://api.weixin.qq.com/cgi-bin/media/upload?type=image',{
            media:path
        },{
            'content-type':'image/png' 
        })

        //{"type":"image","media_id":"mUlBLkIm48uQ_uA1yfv521_cwd7IWKOlGFjavfbdnUKZ4KBzbY1Ok-rMsAKG0JLk","created_at":1698262200,"item":[]}
        return res
    }

    //永久素材上传
    async uploadImage(imagePaths){
        try {
            const res = await this.officialAccount
            .getClient()
            .httpUpload('https://api.weixin.qq.com/cgi-bin/media/uploadimg',[
                '/www/wwwroot/nest.apesk.net/static/post-head.png'
            ],{
                // 'filename':'back-image.png',
                // 'content-type':'image/png' 
            })

            //http://mmbiz.qpic.cn/sz_mmbiz_png/xcFRQm9TQh0UK8G46r58IM5SOZp8rWvTMDImfpmX2lefwhOLCicNobpEcExQHHVBWd0kQwahJOCjvBjdzmaJYicw/0
            return JsonApiResponse.object(res)
        } catch (error) {
            console.log(error)
            return JsonApiResponse.object(error)
        }
    }

    async uploadNews(newses) {
        const res = await this.officialAccount
        .getClient()
        .httpPostJson('https://api.weixin.qq.com/cgi-bin/media/uploadnews',{
            "articles": newses
        })

        //{"status":0,"message":"成功","data":{"type":"news","media_id":"3prqdD8W38nDnrK2h-qnmM8rgu5-hCY5ItnghDrRL7Z7oM8ckx0JnhWIotCtYC70","created_at":1698348318,"item":[]}}
        return res
    }
    
    async sendAll(media_id,send_ignore_reprint=0) {
        const res = await this
        .officialAccount
        .getClient()
        .httpPostJson('https://api.weixin.qq.com/cgi-bin/message/mass/sendall',{
            "filter":{
                "is_to_all":true,
            },
            "mpnews":{
                "media_id":media_id
            },
                "msgtype":"mpnews",
                "send_ignore_reprint":send_ignore_reprint
        })

        return res
    }

    async newsPreivew(media_id)
    {
        let preview = await this
        .officialAccount
        .getClient()
        .httpPostJson('https://api.weixin.qq.com/cgi-bin/message/mass/preview',{
            "touser":"beckham996", 
            "mpnews":{              
              "media_id" : media_id
             },
            "msgtype":"mpnews" 
         })

         return preview
    }

    async newsStatus(msg_id)
    {
        let status = await this
        .officialAccount
        .getClient()
        .httpPostJson('https://api.weixin.qq.com/cgi-bin/message/mass/get',{
            "msg_id": msg_id
         })

         return status
    }

    async send_news(sendPostTask) {
        await this.queue.add('news_send',sendPostTask,{
            removeOnComplete:true,
            delay: 500,
            attempts:1,
            backoff:0
        });
    }

    @Process('news_send')
    async processNewsSend(job: Job<unknown>){
        const sendPostsTask : any = job.data //as PublishPacket
        const office_id = sendPostsTask.office_id
        const news_id = sendPostsTask.news_id
        const record_id = sendPostsTask.record_id
        const knex = knext(this)
        let err : Error = null

        try{
            await (async function(){

            if(!record_id) 
              return

            const record = await knex.fromORM(OfficeNewsSendRecords)
            .where({id:record_id}).getOne()

            if(!record)
              return

            if(!office_id || !news_id)
            {
                throw new Error(JSON.stringify({tip:'参数不正确',params:{office_id,news_id,record_id}}))
            }

            const officeAccount = await knex.fromORM(OfficeAccounts)
            .where({id:office_id})
            .getOne()

            if(!officeAccount) 
                throw new Error(JSON.stringify({tip:'公众账号不存在'}))

            this.officalAccount = new OfficialAccountTemplate({
                app_id  : officeAccount.app_id,
                secret  : officeAccount.secret,
                token   : officeAccount.token,
                aes_key : officeAccount.aes_key
            })

            const result = await knex.fromORM(OfficeNews)
            .withEntity(OfficePosts,'postsPivots',null,'posts','asc')
            .where({id:news_id})
            .getOne()
    
            let sendPosts = []
            for (const key in result.posts) {
                let post = result.posts[key]
                //ENOENT: no such file or directory, open '/www/wwwroot/nest.apesk.net/http:/www.apesk.net/static/post-head-2.jpg'
                
                if(post.thumb_url.startsWith('http'))
                    post.thumb_url = post.thumb_url.substring(post.thumb_url.indexOf('/public'))

                let path = join(process.cwd(),post.thumb_url)
                post.thumb_url = path
                let res = await this.uploadTempMedia(path)
                if(res.errcode) 
                    throw new Error(JSON.stringify({tip:'群发图文素材错误',message:`${JSON.stringify(res)}`}))

                post.thumb_media_id = res.media_id
    
                let temp = {
                    "thumb_media_id": res.media_id,
                    "author":"掌聘JOB",		
                    "title":post.title,
                    "content":post.html,		 
                    "digest":post.digest,
                    "show_cover_pic":1,
                    "need_open_comment":1,
                    "only_fans_can_comment": 0
                }
     
                sendPosts.push(temp);
            }
    
            //上传图文,建立图文临时素材
            let uploadResult = await this.uploadNews(sendPosts)
            if(uploadResult.errcode) 
                throw new Error(JSON.stringify({tip:'上传图文错误',message:`${JSON.stringify(uploadResult)}`}))
    
            //群发图文素材
            let sendResult = await this.sendAll(uploadResult.media_id)
            if(sendResult.errcode) 
                throw new Error(JSON.stringify({tip:'群发错误',message:`${JSON.stringify(sendResult)}`}))

            //查询图文群发状态
            let newsStatus = await this.newsStatus(sendResult.msg_id)

            await knex.fromORM(OfficeNewsSendRecords).update({
                news_id: news_id,
                msg_id: sendResult.msg_id,
                media_id: uploadResult.media_id,
                msg_status: newsStatus.msg_status,
                msg_ok:1
            })
            .where({id:record_id})
            .then()
            }).apply(this)
        }catch(_err) {
            try{
                await knex.fromORM(OfficeNewsSendRecords)
                .update({
                    exception: _err.message,
                    msg_ok:0
                })
                .where({id:record_id})
                .then()
            }
            catch(_err)
            {
                console.log(_err)
            }
        }
    }
}